#pragma once
#include <iostream>
#include <string>
#include<functional>
#include <cstdlib>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include<sys/wait.h>
#include <unistd.h>
#include<pthread.h>
#include "Log.hpp"
#include "InetAddr.hpp"

enum ERRor
{
    USAGE_ERR = 1,
    SOCKET_ERR,
    BIND_ERR,
    LISTEN_ERR,

};
class TcpServer;//声明一下

struct threaddata
{
    threaddata(int fd,InetAddr&addr,TcpServer*tp):_fd(fd),_addr(addr),_self(tp)
    {}
    int _fd;
    InetAddr _addr;
    TcpServer* _self;
};

using func_t = std::function<std::string(std::string)>;

class TcpServer
{
public:
    TcpServer(uint16_t port,func_t func) : _port(port), _listensock(-1),_func(func)
    {
    }
    void InitServer()
    {
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock < 0)
        {
            LOG(FATAL, "socket err");
            exit(SOCKET_ERR);
        }
        LOG(INFO, "socket success");
        struct sockaddr_in server;
        bzero(&server, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(_port);
        server.sin_addr.s_addr = INADDR_ANY;
        int n = bind(_listensock, (struct sockaddr *)&server, sizeof(server));
        if (n < 0)
        {
            LOG(FATAL, "bind err");
            exit(BIND_ERR);
        }
        LOG(INFO, "bind success");
        n = listen(_listensock, 16);
        if (n < 0)
        {
            LOG(FATAL, "listen err");
            exit(LISTEN_ERR);
        }
        LOG(INFO, "listen success");
    }
    void service(int fd, InetAddr addr)
    {
        LOG(INFO, "server get a new link,ip is %s,port is %d", addr.Ip().c_str(), addr.Port());
        while (true)
        {
            char buffer[1024];
            int n = recv(fd, buffer, sizeof(buffer) - 1,0);
            if (n > 0)
            {
                buffer[n] = 0;
                LOG(INFO, "[%s:%d]#%s", addr.Ip().c_str(), addr.Port(), buffer);

                std::string res=_func(std::string(buffer));
                send(fd,res.c_str(),res.size(),0);
            }
            else if (n < 0) // 读取出错
            {
                LOG(ERROR, "read error");
                break;
            }
            else // n==0 client退出&&关闭连接
            {
                LOG(INFO, "[%s,%d] quit", addr.Ip().c_str(), addr.Port());
                break;
            }
        }
    }
    static void*newthreaddo(void*arg)
    {
        pthread_detach(pthread_self());
        threaddata*ptd=static_cast<threaddata*>(arg);
        ptd->_self->service(ptd->_fd,ptd->_addr);
        delete ptd;
        return nullptr;
    }
    void StartServer()
    {
        while (true)
        {
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int fd = accept(_listensock, (struct sockaddr *)&client, &len);
            if (fd < 0)
            {
                LOG(WARNING, "accept err");
                continue;
            }
            InetAddr addr(client);

            pthread_t t;//多线程
            threaddata* ptd=new threaddata(fd,addr,this);
            pthread_create(&t,nullptr,newthreaddo,ptd);

        }
    }

    ~TcpServer()
    {
    }

private:
    uint16_t _port;
    int _listensock;
    func_t _func;
};